const BaseService = require('./base');
const fs = require('fs-extra');
const path = require('path');
const core = require('@babel/core');
const types = require('@babel/types');
let routerPlugin = (name) => ({
    visitor: {
        BlockStatement(path) {
            let { node } = path;
            node.body = [
                ...node.body,
                types.expressionStatement(
                    types.callExpression(
                        types.memberExpression(
                            types.identifier('router'),
                            types.identifier('resources')
                        ),
                        [
                            types.stringLiteral(name),
                            types.stringLiteral(`/${name}`),
                            types.memberExpression(
                                types.identifier('controller'),
                                types.identifier(name)
                            )
                        ]
                    )
                )
            ];
        }
    }
})
module.exports = class extends BaseService {
    entity = 'entity'
    async create(entity) {
        const { app } = this;
        let fields = entity.fields;
        for (const key in entity) {
            switch (key) {
                case 'fields':
                case 'page':
                case 'record':
                    entity[key] = JSON.stringify(entity[key]);
                    break;
                default:
                    break;
            }
        }
        entity.created = app.mysql.literals.now;
        entity.updated = app.mysql.literals.now;
        const insertResult = await this.app.mysql.insert(this.entity, entity);
        let existTables = await this.app.mysql.select('information_schema.tables', { where: { TABLE_SCHEMA: 'antd', TABLE_NAME: entity.name } });
        if (existTables.length === 0) {
            fields = typeof fields === 'string' ? JSON.parse(fields) : fields;
            const columns = fields.map(getColumn);
            const sql = `CREATE TABLE ${entity.name}(
                    id int(11) NOT NULL AUTO_INCREMENT,
                    ${columns.length > 0 ? columns.join(',') + ',' : ''}
                    created DATETIME,
                    updated DATETIME,
                    PRIMARY KEY(id)
                ) ENGINE = InnoDB  DEFAULT CHARSET = utf8mb4;
                `
            await this.app.mysql.query(sql);
        }
        //添加菜单
        await this.app.mysql.insert('menu', {
            name: entity.title,
            path: `/entity/view?id=${insertResult.insertId}&name=${entity.name}`,
            created: app.mysql.literals.now,
            updated: app.mysql.literals.now
        });
        //生成代码
        const controllerTemplate = await fs.readFile(path.join(__dirname, '../view/controller.js'), 'utf8');
        const serviceTemplate = await fs.readFile(path.join(__dirname, '../view/service.js'), 'utf8');
        const controller = await this.ctx.renderString(controllerTemplate, { name: entity.name });
        const service = await this.ctx.renderString(serviceTemplate, { name: entity.name });
        await fs.writeFile(path.join(__dirname, `../controller/${entity.name}.js`), controller, 'utf8');
        await fs.writeFile(path.join(__dirname, `../service/${entity.name}.js`), service, 'utf8');
        const routerSource = await fs.readFile(path.join(__dirname, '../router.js'), 'utf8');
        let targetSource = await core.transformAsync(routerSource, {
            plugins: [routerPlugin(entity.name)]
        });
        await fs.writeFile(path.join(__dirname, '../router.js'), targetSource.code, 'utf8');
    }
    async show(id) {
        const entity = await this.app.mysql.get(this.entity, { id });
        for (const key in entity) {
            switch (key) {
                case 'fields':
                case 'page':
                case 'record':
                    entity[key] = JSON.parse(entity[key]);
                    break;
                default:
                    break;
            }
        }
        return entity;
    }
    async update(entity) {
        const fields = entity.fields;
        for (const key in entity) {
            switch (key) {
                case 'fields':
                case 'page':
                case 'record':
                    entity[key] = JSON.stringify(entity[key]);
                    break;
                default:
                    break;
            }
        }
        delete entity.created;
        delete entity.updated;
        await this.app.mysql.update(this.entity, entity);
        const columns = await this.app.mysql.select('information_schema.COLUMNS', { where: { TABLE_SCHEMA: this.config.mysql.client.database, TABLE_NAME: entity.name } });
        const newFields = fields.filter(field => !columns.find(column => column.COLUMN_NAME === field.name));
        if (newFields.length > 0) {
            const newColumns = newFields.map(getColumn);
            const sql = `ALTER TABLE ${entity.name} ADD (${newColumns.join(',')});`
            await this.app.mysql.query(sql);
        }
    }
}

function getColumn(field) {
    let dataType = 'varchar(255)';
    switch (field.type) {
        case 'number':
            dataType = 'int(11)';
            break;
        case 'select':
            dataType = 'int(11)';
            break;
        case 'datetime':
            dataType = 'datetime';
            break;
        case 'switch':
            dataType = 'tinyint(1)';
        default:
            break;
    }
    return `${field.name} ${dataType}`;
}